package com.learning.optimize.jdk.proxy;

import com.google.common.collect.Lists;
import com.google.common.reflect.Reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;

/**
 * ClassName: DynamicProxy
 * Description: 动态代理
 * <p>
 * https://www.ibm.com/developerworks/cn/java/j-lo-proxy1/index.html
 * Date: 2018/7/19 17:22 【需求编号】
 *
 * @author Sam Sho
 * @version V1.0.0
 */
public class DynamicProxy {

    public static void main(String[] args) {
//        test();
//        test2();
        test3();
    }

    /**
     * 简单使用
     */
    static void test() {

        ArrayList<String> target = Lists.newArrayList();

        Collection collectionProxy = (Collection) Proxy.newProxyInstance(Collection.class.getClassLoader(), new Class[]{Collection.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("proxy.getClass().getName(): " + proxy.getClass().getName());
                System.out.println("method.getName(): " + method.getName());

                if (Objects.isNull(args)) {
                    System.out.println("args: " + Arrays.toString(args));
                }
                Object object = method.invoke(target, args);
                return object;
            }
        });

        collectionProxy.add("你好，代理");

    }

    /**
     * Guava 的封装方法
     */
    static void test2() {
        ArrayList<Object> list = Lists.newArrayList();
        Collection collection = Reflection.newProxy(Collection.class, (proxy, method, args) -> {
            System.out.println("*********** Before invoke *****************");
            Object object = method.invoke(list, args);
            System.out.println("*********** After invoke *****************");
            return object;
        });

        collection.add("Guava Proxy");
    }

    /**
     * 动态代理类的构造函数与方法
     * 通过这些，大概可以猜测动态代理类源码：
     *
     */
    static void test3() {
        Class<?> proxyClass = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);

        System.out.println("----------1、查看动态代理类的构造方法 constructors-------------");

        Constructor<?>[] constructors = proxyClass.getConstructors();
        for (Constructor<?> constructor : constructors) {
            String name = constructor.getName();
            System.out.println("代理类的构造方法的名字：  " + name);


            // 拼参数列表
            StringBuilder tBuilder = new StringBuilder(name);
            tBuilder.append('(');
            // 构造方法的参数
            Class<?>[] clazzParams = constructor.getParameterTypes();
            for (Class<?> clazzParam : clazzParams) {
                // 构造方法的参数
                System.out.println("构造方法参数的类型：  " + clazzParam.getName());
                tBuilder.append(clazzParam.getName()).append(',');
            }

            // 有参数的时候
            if (clazzParams != null && clazzParams.length != 0) {
                // 去掉最后一个逗号
                tBuilder.deleteCharAt(tBuilder.length() - 1);
            }
            tBuilder.append(')');
            System.out.println(tBuilder);
        }
        /*
         输出：
         代理类的构造方法的名字：  com.sun.proxy.$Proxy0
         构造方法参数的类型：  java.lang.reflect.InvocationHandler
         com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler)
        */

        System.out.println("----------2、动态代理类的方法以及参数-------------");

        //利用反射得到所有的方法
        Method[] methods = proxyClass.getMethods();
        for (Method method : methods) {
            String name = method.getName();
            StringBuilder tBuilder = new StringBuilder(name);
            tBuilder.append('(');
            //得到方法的参数类型
            Class<?>[] clazzParams = method.getParameterTypes();
            for (Class<?> clazzParam : clazzParams) {
                tBuilder.append(clazzParam.getName()).append(',');
            }

            if (clazzParams != null && clazzParams.length != 0) {
                tBuilder.deleteCharAt(tBuilder.length() - 1);
            }
            tBuilder.append(')');
            System.out.println(tBuilder);
        }

        /*
            ----------2、动态代理类的方法以及参数-------------
            add(java.lang.Object)
            remove(java.lang.Object)
            equals(java.lang.Object)
            toString()
            hashCode()
            clear()
            contains(java.lang.Object)
            isEmpty()
            iterator()
            size()
            toArray([Ljava.lang.Object;)
            toArray()
            spliterator()
            addAll(java.util.Collection)
            stream()
            forEach(java.util.function.Consumer)
            containsAll(java.util.Collection)
            removeAll(java.util.Collection)
            removeIf(java.util.function.Predicate)
            retainAll(java.util.Collection)
            parallelStream()
            isProxyClass(java.lang.Class)
            newProxyInstance(java.lang.ClassLoader,[Ljava.lang.Class;,java.lang.reflect.InvocationHandler)
            getProxyClass(java.lang.ClassLoader,[Ljava.lang.Class;)
            getInvocationHandler(java.lang.Object)
            wait()
            wait(long,int)
            wait(long)
            getClass()
            notify()
            notifyAll()
         */
    }

    static void test4() {

    }
}
